package easier.app.x.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;

/**
 * 用于 service 执行任务,能执行跨进程任务,
 * 实现{@link #toString(int, Object)}和{@link #fromString(int, String)}用于转换数据进行跨进程通信
 * 使用{@link #sendCommand(Context, Class, int, Object)}发送命令
 *
 * @author wuxio 2018-06-11:16:51
 */
public class CommandService extends Service {

    private static final String KEY_COMMAND = "service.command";
    private static final String KEY_COMMAND_WHAT = "service.command.what";

    /**
     * 辅助处理命令
     */
    private CommandHandler mCommandHandler;

    /**
     * 发送任务给service执行
     */
    public static < T extends CommandService > void sendCommand(
        Context context,
        Class< T > commandServiceClazz,
        int what,
        Object extra ) {

        try {
            String s = commandServiceClazz.newInstance().toString( what, extra );
            Intent intent = new Intent( context, commandServiceClazz );
            intent.putExtra( KEY_COMMAND, what );
            intent.putExtra( KEY_COMMAND_WHAT, s );
            context.startService( intent );
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    public CommandService() {

    }

    @Override
    public void onCreate() {

        super.onCreate();
        mCommandHandler = new CommandHandler( this );
    }

    @CallSuper
    @Override
    public int onStartCommand( Intent intent, int flags, int startId ) {

        if ( intent == null ) {
            return super.onStartCommand( intent, flags, startId );
        }

        int command = intent.getIntExtra( KEY_COMMAND, -1 );
        String extra = intent.getStringExtra( KEY_COMMAND_WHAT );

        Object data = null;

        if ( !TextUtils.isEmpty( extra ) ) {
            data = fromString( command, extra );
        }

        mCommandHandler.newCommandArrive( command, data );

        return super.onStartCommand( intent, flags, startId );
    }

    /**
     * 收到带附件的command
     *
     * @param what   标识
     * @param bundle 附件包
     */
    protected void onCommandReceive( int what, Object bundle ) {}

    /**
     * @param object 用于序列化数据传输到service,{@link #sendCommand(Context, Class, int, Object)}
     *
     * @return 序列化数据
     */
    protected String toString( int command, Object object ) {

        return object.toString();
    }

    /**
     * @param s 反序列化数据,将{@link #toString(int, Object)}转换为数据,{@link #onStartCommand(Intent, int, int)}
     *
     * @return 数据
     */
    protected Object fromString( int command, String s ) {

        return s;
    }

    /**
     * don,t  use this
     */
    @Nullable
    @Override
    public IBinder onBind( Intent intent ) {

        return null;
    }

    @Override
    public void onDestroy() {

        if ( mCommandHandler != null ) {
            mCommandHandler.removeCallbacksAndMessages( null );
            mCommandHandler.mCommandService = null;
        }

        super.onDestroy();
    }

    /**
     * 执行任务,使用 Handler 执行任务,防止阻塞{@link #onStartCommand(Intent, int, int)}
     */
    private static class CommandHandler extends Handler {

        private final static int WHAT_OBJECT_COMMAND = 0b100000111;

        private CommandService mCommandService;

        private CommandHandler( CommandService commandService ) {

            super( Looper.getMainLooper() );
            mCommandService = commandService;
        }

        private void newCommandArrive( int what, Object o ) {

            Message obtain = Message.obtain();
            obtain.what = WHAT_OBJECT_COMMAND;
            obtain.arg1 = what;
            obtain.obj = o;
            sendMessage( obtain );
        }

        @Override
        public void handleMessage( Message msg ) {

            if ( msg.what == WHAT_OBJECT_COMMAND ) {
                try {
                    mCommandService.onCommandReceive( msg.arg1, msg.obj );
                } catch ( Exception e ) {
                    e.printStackTrace();
                }
            }
        }
    }
}